<template>
  <div class="m-designer">
    <div v-for="(item, i) in designerCardList" :key="i" class="m-designer-card">
      <div class="m-designer-card-wrapper">
        <div class="title">
          <van-field
            v-model="item.options.label"
            type="textarea"
            rows="1"
            autosize
            maxlength="200"
            :label="labelNum(i + 1)"
            placeholder="请输入标题"
            :required="item.options.required"
            :border="false"
            :readonly="disabled"
          />
          <van-icon name="jiantoushang" class-prefix="m-icon" :color="iconColor(i, 0)" @click="moveUp(i)" />
          <van-icon name="jiantouxia" class-prefix="m-icon" :color="iconColor(i, 1)" @click="moveDown(i)" />
        </div>
        <div v-if="item.type === 'picture'">
          <div class="uploader-card">
            <van-icon name="photograph" />
            <div>
              <span>{{ item.options.tip }}</span>
            </div>
          </div>
        </div>
        <div v-else-if="item.type === 'fileupload'">
          <div v-if="item.options.listType === 'picture-card'" class="uploader-card">
            <van-icon name="photograph" />
            <div>
              <span>{{ item.options.tip }}</span>
            </div>
          </div>
          <div v-else class="uploader-file">
            <van-button icon="plus" type="primary" size="small" disabled>上传文件</van-button>
            <div class="tip">
              <span>{{ item.options.tip }}</span>
            </div>
          </div>
        </div>
        <div v-else-if="item.type === 'signature'" class="signature">
          <van-icon name="edit" class="icon" />
          <div>
            <span>{{ item.options.signText }}</span>
          </div>
        </div>
        <div v-else class="value">
          <van-field
            v-if="item.type === 'textarea'"
            type="textarea"
            rows="1"
            autosize
            :maxlength="item.options.maxlength"
            show-word-limit
            readonly
            :placeholder="item.options.placeholder"
            @click-input.stop="onShowTextareaSetting(item)"
          />
          <template v-else-if="item.options.optionItems">
            <van-field
              v-for="(opt, n) in item.options.optionItems"
              :key="n"
              v-model="opt.label"
              :placeholder="item.options.placeholder"
              :readonly="disabled"
            >
              <template #left-icon>
                <van-icon name="remove" class-prefix="m-icon" color="#FF4848" @click="delOptionItem(item, n)" />
              </template>
            </van-field>
          </template>
          <van-field
            v-else
            readonly
            :placeholder="item.options.placeholder"
            @click-input.stop="onShowTextareaSetting(item)"
          />
        </div>
        <div class="footer">
          <div class="left">
            <div v-if="item.options.optionItems">
              <span class="primary" @click="addOptionItem(item)"><van-icon name="add-o" />选项</span>
            </div>
            <div v-if="item.type === 'picture'" class="input">
              <van-field v-model="item.options.accept" maxlength="100" placeholder="限制图片类型 如：.jpg,.jpeg,.png" />
            </div>
            <div v-if="item.type === 'fileupload'" class="input">
              <van-field v-model="item.options.accept" maxlength="100" placeholder="限制文件类型 如：.doc,.docx,.pdf" />
            </div>
          </div>
          <div class="right">
            <span><van-checkbox v-model="item.options.required" :disabled="disabled">必填</van-checkbox></span>
            <van-icon name="ellipsis" @click="onShowAction(item)" />
          </div>
        </div>
      </div>
    </div>
    <div class="m-designer-btn-add" @click="onShowAdd"><van-icon name="plus" />{{ addBtn }}</div>
    <van-popup v-model:show="showAdd" round position="bottom">
      <div class="m-designer-create">
        <div class="m-designer-create-header">添加表单项类型</div>
        <div class="m-designer-create-wrapper">
          <div class="item" @click="addTextarea">
            <m-icon name="input-textarea" />
            <div>文本填空</div>
          </div>
          <div class="item" @click="addNumber">
            <m-icon name="input-number" />
            <div>数字填空</div>
          </div>
          <div class="item" @click="addRadio">
            <m-icon name="input-radio" />
            <div>单选</div>
          </div>
          <div class="item" @click="addCheckbox">
            <m-icon name="input-checkbox" />
            <div>多选</div>
          </div>
          <div class="item" @click="addSelect">
            <m-icon name="input-select" />
            <div>选择列表</div>
          </div>
          <div class="item" @click="addPicture">
            <m-icon name="input-picture" />
            <div>图片</div>
          </div>
          <div class="item" @click="addFileupload">
            <m-icon name="input-fileupload" />
            <div>附件</div>
          </div>
          <div class="item" @click="addSignature">
            <m-icon name="input-signature" />
            <div>签名</div>
          </div>
        </div>
      </div>
    </van-popup>
    <van-action-sheet
      v-model:show="showAction"
      :actions="actions"
      cancel-text="取消"
      close-on-click-action
      @select="onActionSelect"
    />
    <van-dialog v-model:show="showDialog" title="选项设置" width="280" show-cancel-button>
      <div v-if="selected.type === 'textarea'" class="dialog-content">
        <van-field
          v-model="selected.options.maxlength"
          type="digit"
          :min="10"
          :max="3000"
          label="最大字符数"
          placeholder="请输入整数"
        />
      </div>
      <div v-if="selected.type === 'input' && selected.options.type === 'number'" class="dialog-content">
        <van-field
          v-model="selected.options.min"
          type="digit"
          :min="0"
          :max="selected.options.max"
          label="最小值"
          placeholder="请输入整数"
        />
        <van-field
          v-model="selected.options.max"
          type="digit"
          :min="selected.options.min"
          :max="999999999"
          label="最大值"
          placeholder="请输入整数"
        />
      </div>
    </van-dialog>
  </div>
</template>

<script>
import _ from 'lodash'
import { ref, computed, onMounted } from 'vue'
import { defaultFormConfig } from '@/config/formConfig'
import { showToast } from 'vant'

export default {
  props: {
    /** 配置双向绑定 */
    modelValue: {
      type: Object,
      default: () => {}
    },
    /** 添加按钮名称 */
    addBtn: {
      type: String,
      default: '提交项'
    },
    /** 禁止修改 */
    disabled: {
      type: Boolean,
      default: false
    }
  },
  emits: ['update:modelValue'],
  setup(props, { emit }) {
    /** 表单配置项初始化不再更新 */
    const formConfig = _.defaultsDeep(
      props.modelValue.formConfig || {
        h5: {
          labelWidth: 80, // 标签宽度
          labelPosition: 'top', // 标签位置 left right top
          inputAlign: 'right' // 输入框对齐方式 left center right
        }
      },
      defaultFormConfig
    )

    /** 初始化绑定格式异常处理 */
    if (!Array.isArray(props.modelValue.widgetList)) {
      emit('update:modelValue', { widgetList: [], formConfig })
    }

    /** 自定义表单组件列表 */
    const designerCardList = computed(() => props.modelValue.widgetList)

    /** 生成唯一ID */
    const generateId = () => {
      return Math.floor(Math.random() * 100000 + Math.random() * 20000 + Math.random() * 5000)
    }

    /** 添加自定义组件面板 */
    const showAdd = ref(false)
    const onShowAdd = () => {
      if (props.disabled) return false
      showAdd.value = true
    }

    /** 添加文本输入组件 */
    const addInput = () => {
      const id = 'input' + generateId()
      designerCardList.value.push({
        id,
        type: 'input',
        name: '文本输入',
        icon: 'input-text',
        options: {
          name: id,
          label: '',
          defaultValueType: 0, // 0自定义 1公式编辑
          defaultValue: '',
          defaultValueFunc: '', // 公式表达式
          maxlength: '20',
          showWordLimit: false,
          placeholder: '可以填写任意文本',
          append: '',
          disabled: false,
          readonly: false,
          clearable: false,
          workflow: true, // 加入审批流程条件使用
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    /** 添加多行输入组件 */
    const addTextarea = () => {
      const id = 'textarea' + generateId()
      designerCardList.value.push({
        id,
        type: 'textarea',
        name: '多行输入',
        icon: 'input-textarea',
        options: {
          name: id,
          label: '',
          defaultValue: '',
          maxlength: '3000',
          rows: 3,
          autosize: true,
          showWordLimit: true,
          ellipsis: 3, // 详情展示的行数
          expandTips: '展开',
          retractTips: '收起',
          placeholder: '可以填写任意文本',
          disabled: false,
          readonly: false,
          workflow: false,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    /** 添加数字输入组件 */
    const addNumber = () => {
      const id = 'number' + generateId()
      designerCardList.value.push({
        id,
        type: 'number',
        name: '数字输入',
        icon: 'input-number',
        options: {
          name: id,
          label: '',
          defaultValue: 0,
          min: 0,
          max: 9999,
          placeholder: '只能填写数字',
          append: '',
          disabled: false,
          readonly: false,
          workflow: true,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }

    /** 添加单项选择组件 */
    const addRadio = () => {
      const id = 'radio' + generateId()
      designerCardList.value.push({
        type: 'radio',
        name: '单项选择',
        icon: 'input-radio',
        options: {
          name: id,
          label: '',
          defaultValue: '1',
          optionItems: [
            { label: '选项一', value: '1' },
            { label: '选项二', value: '2' },
            { label: '选项三', value: '3' }
          ],
          inline: true, // 是否显示为一行
          disabled: false,
          workflow: true,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    /** 添加多项选择组件 */
    const addCheckbox = () => {
      const id = 'checkbox' + generateId()
      designerCardList.value.push({
        id,
        type: 'checkbox',
        name: '多项选择',
        icon: 'input-checkbox',
        options: {
          name: id,
          label: '',
          defaultValue: [],
          optionItems: [
            { label: '选项一', value: '1' },
            { label: '选项二', value: '2' },
            { label: '选项三', value: '3' }
          ],
          inline: true, // 是否显示为一行
          disabled: false,
          workflow: true,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    /** 添加下拉框选择 */
    const addSelect = () => {
      const id = 'select' + generateId()
      designerCardList.value.push({
        id,
        type: 'select',
        name: '选择列表',
        icon: 'input-select',
        options: {
          name: id,
          label: '',
          defaultValue: '1',
          optionItems: [
            { label: '选项一', value: '1' },
            { label: '选项二', value: '2' },
            { label: '选项三', value: '3' }
          ],
          placeholder: '请选择',
          disabled: false,
          clearable: false,
          workflow: true,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    /** 添加图片组件 */
    const addPicture = () => {
      const id = 'picture' + generateId()
      designerCardList.value.push({
        id,
        type: 'picture',
        name: '图片',
        icon: 'input-picture',
        options: {
          name: id,
          label: '',
          inputAlign: 'left',
          defaultValue: [],
          action: '/api/basic/image-manage/upload',
          actionBlob: '/api/basic/image-manage',
          camera: false, // 手机端仅拍照上传
          reduce: 1, // 使用压缩图片上传 0原图 1高清无损 2高质量
          limit: 10,
          fileMaxSize: 10,
          accept: '',
          tip: '最多上传10个图片',
          disabled: false,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    /** 添加附件组件 */
    const addFileupload = () => {
      const id = 'fileupload' + generateId()
      designerCardList.value.push({
        id,
        type: 'fileupload',
        name: '附件',
        icon: 'input-fileupload',
        options: {
          name: id,
          label: '',
          inputAlign: 'left',
          defaultValue: [],
          action: '/api/basic/image-manage/upload',
          actionBlob: '/api/basic/image-manage',
          limit: 5,
          fileMaxSize: 20,
          listType: 'picture',
          accept: '',
          tip: '最多上传5个附件',
          disabled: false,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }
    const addSignature = () => {
      const id = 'signature' + generateId()
      designerCardList.value.push({
        id,
        type: 'signature',
        name: '签名',
        icon: 'input-signature',
        options: {
          name: id,
          label: '',
          type: 'png',
          penColor: '#000',
          lineWidth: 3,
          backgroundColor: '',
          clearButtonText: '清空',
          confirmButtonText: '确认',
          signText: '点击去签名',
          reSignText: '重新签名',
          disabled: false,
          required: false,
          requiredMessage: '不能为空！'
        }
      })
      showAdd.value = false
    }

    /** 组件序号排序显示 */
    const labelNum = (index) => (index < 10 ? `0${index}.` : `${index}.`)

    /** 上下按钮颜色 */
    const iconColor = (index, last) => {
      if (last) {
        if (index === designerCardList.value.length - 1) {
          return '#999'
        }
      } else {
        if (index === 0) {
          return '#999'
        }
      }
      return '#4A4A4A'
    }

    /** 添加选项 */
    const addOptionItem = (item) => {
      if (props.disabled) return false
      if (Array.isArray(item.options.optionItems)) {
        const last = item.options.optionItems[item.options.optionItems.length - 1]
        if (last) {
          item.options.optionItems.push({ label: '', value: Number(last.value) + 1 })
        } else {
          item.options.optionItems.push({ label: '', value: Number(item.options.optionItems.length) + 1 })
        }
      }
    }
    /** 移除选项 */
    const delOptionItem = (item, index) => {
      if (props.disabled) return false
      if (Array.isArray(item.options.optionItems)) {
        if (item.options.optionItems.length <= 2) {
          return showToast('至少要保留两个选项')
        }
        item.options.optionItems.splice(index, 1)
      }
    }

    /** 向上移动排序 */
    const moveUp = (index) => {
      if (props.disabled) return false
      if (index === 0) {
        return false
      }
      designerCardList.value.splice(
        index,
        1,
        ...designerCardList.value.splice(index - 1, 1, designerCardList.value[index])
      )
    }

    /** 向下移动排序 */
    const moveDown = (index) => {
      if (props.disabled) return false
      if (index === designerCardList.value.length - 1) {
        return false
      }
      designerCardList.value.splice(
        index,
        1,
        ...designerCardList.value.splice(index + 1, 1, designerCardList.value[index])
      )
    }

    /** 弹窗修改配置项 */
    const showDialog = ref(false)
    const onShowTextareaSetting = (item) => {
      if (props.disabled) return false
      selected.value = item
      console.log('item :>> ', item)
      showDialog.value = true
    }

    /** 弹窗更多操作面板 */
    const showAction = ref(false)
    const selected = ref(null)
    const actions = [{ name: '删除' }]
    /** 打开操作面板 */
    const onShowAction = (item) => {
      if (props.disabled) return false
      selected.value = item
      showAction.value = true
    }
    /** 操作面板选项触发事件 */
    const onActionSelect = (action, index) => {
      if (props.disabled) return false
      if (selected.value) {
        const n = designerCardList.value.findIndex((m) => m === selected.value)
        designerCardList.value.splice(n, 1)
      }
    }

    /** 校验表单组件设置项检查 */
    const verification = (message = true) => {
      return new Promise((resolve, reject) => {
        const checked = []
        // 标题不能为空
        designerCardList.value.forEach((e, index) => {
          if (!e.options.label) {
            checked.push(index + 1)
          }
        })
        if (checked.length > 0) {
          if (message) {
            showToast(`第 ${checked.join('、')} 个标题不能为空`)
          }
          return reject({ label: true, error: checked })
        }
        // 选项不能为空
        designerCardList.value.forEach((e, index) => {
          if (e.options.optionItems) {
            const option = e.options.optionItems.some((v) => !v.label)
            if (option) {
              checked.push(index + 1)
            }
          }
        })
        if (checked.length > 0) {
          if (message) {
            showToast(`第 ${checked.join('、')} 个选项名称不能为空`)
          }
          return reject({ option: true, error: checked })
        }
        resolve()
      })
    }

    onMounted(() => {
      // console.log('designerCardList :>> ', designerCardList.value)
    })

    return {
      designerCardList,
      labelNum,
      iconColor,
      addOptionItem,
      delOptionItem,
      moveUp,
      moveDown,
      showAdd,
      showDialog,
      showAction,
      selected,
      actions,
      onShowAdd,
      onShowTextareaSetting,
      onShowAction,
      onActionSelect,
      addInput,
      addNumber,
      addTextarea,
      addRadio,
      addCheckbox,
      addSelect,
      addPicture,
      addFileupload,
      addSignature,
      verification
    }
  }
}
</script>

<style lang="scss">
.m-designer {
  position: relative;
  padding: 16px;
  font-size: 14px;

  &-card {
    background: #f4f5f9;
    border-radius: 8px;
    padding: 8px 16px;
    margin-bottom: 10px;
    &-wrapper {
      font-size: 14px;

      .title {
        display: flex;
        align-items: center;
        .van-cell {
          padding: 8px 0;
          background: transparent;
          font-weight: 500;
          font-size: 14px;
          color: #4a4a4a;
        }
        .van-field__label {
          width: auto;
          margin-right: 8px;
          color: #000;
        }
        .m-icon {
          margin-left: 8px;
          font-size: 14px;
        }
      }
      .value {
        border-radius: 8px;
        background: #fff;
        margin: 8px 0;
        .van-cell {
          background: transparent;
          padding: 8px 16px;
        }
        .van-field__left-icon {
          margin-right: 10px;
        }
        .m-icon {
          font-size: 12px;
        }
      }
      .uploader-card {
        display: flex;
        flex-direction: column;
        border-radius: 8px;
        width: 107px;
        height: 107px;
        background: #fff;
        margin: 8px 0;
        align-items: center;
        justify-content: center;
        color: #dcdee0;
        font-size: 24px;
        padding: 0 4px;
        box-sizing: content-box;

        span {
          font-weight: 500;
          font-size: 10px;
          color: #999999;
          line-height: 10px;
        }
      }
      .uploader-file {
        margin: 8px 0;
        .tip {
          font-weight: 500;
          font-size: 10px;
          color: #999999;
          margin-top: 10px;
        }
      }
      .signature {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        border-radius: 8px;
        width: 80px;
        height: 80px;
        background: #fff;
        color: #999;
        span {
          font-weight: 500;
          font-size: 10px;
          color: #999999;
          line-height: 10px;
        }
        .icon {
          font-size: 18px;
        }
      }
      .footer {
        padding: 8px 0;
        display: flex;
        font-size: 12px;
        font-weight: 500;

        .left {
          flex: 1;
          color: #999999;
          .primary {
            color: var(--van-primary-color);
          }
          .input {
            margin-right: 8px;
            .van-field {
              padding: 2px 8px;
              border-radius: 8px;
            }
          }
        }

        .right {
          display: flex;
          align-items: center;
        }

        .van-checkbox {
          font-size: 12px;
        }
        .van-checkbox__icon {
          font-size: 12px;
        }
        .van-icon-add-o {
          margin-right: 4px;
        }
        .van-icon-ellipsis {
          margin-left: 8px;
          font-size: 14px;
          line-height: 20px;
        }
        .van-checkbox__label {
          margin-left: 4px;
        }
        .van-checkbox__icon--checked .van-icon {
          color: var(--van-checkbox-checked-icon-color);
          background-color: #fff;
          border-color: var(--van-checkbox-checked-icon-color);
        }
        .van-checkbox__label {
          color: #999;
        }
      }
    }
  }

  &-btn-add {
    background: #f4f5f9;
    border-radius: 8px;
    font-weight: 500;
    font-size: 14px;
    color: var(--van-primary-color);
    line-height: 14px;
    padding: 16px;
    display: flex;
    justify-content: center;
    .van-icon-plus {
      margin-right: 4px;
    }
  }

  &-create {
    position: relative;
    overflow: hidden;
    &-header {
      position: relative;
      padding: 15px;
      color: #999;
      display: flex;
      justify-content: center;
      &::after {
        position: absolute;
        content: '';
        right: 0;
        left: 0;
        bottom: 0;
        border-bottom: 1px solid var(--van-cell-border-color);
        transform: scaleY(0.5);
      }
    }
    &-wrapper {
      display: flex;
      flex-wrap: wrap;
      align-content: flex-start;
      padding: 15px;
      height: 500px;
      overflow-y: auto;
      box-sizing: border-box;

      .item {
        width: 75px;
        height: 75px;
        border-radius: 8px;
        background: #f4f5f9;
        margin-right: 15px;
        margin-bottom: 15px;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        font-size: 13px;
        font-weight: 500;

        &:nth-child(4n) {
          margin-right: 0;
        }
        .svg-icon {
          margin-bottom: 8px;
          font-size: 22px;
        }
      }
    }
  }

  .dialog-content {
    padding: 15px;
  }
}
</style>
